# -*- encoding: utf-8 -*-
"""
File Name: alarms_manager
Description:
Author : 'lirui'
date: 11/1/2024
Contact: marjey_lee@163.com
Change Activity:
11/1/2024:
"""
import json

import ll
from ll.third_party.redis_util.redis_client import RedisClient
from projects.monitoring.alarms_manager.services.severity_classify import AlarmsSeverityClassifier
from projects.monitoring.alarms_manager.utils.alarm_sender import AlarmSender
from projects.monitoring.common.config.redis import REDIS_SERVER_INFO
from projects.monitoring.common.do.alarm import Alarm
from projects.monitoring.common.utils.redis_keys_util import RedisKeysUtil


class CurrentAlarmsManager:
    def __init__(self, subscribe_type, subscribe_alarms: list[Alarm]):
        self.subscribe_type = subscribe_type
        self.all_subscribe_alarms = self._format_subscribe_alarms(subscribe_alarms)
        self.warning_alarms, self.mute_alarms = self._classify_alarms()
        self.redis_client = self._get_client()
        self.current_redis_subscribe_alarms = self._get_current_warning_from_redis()

    def _classify_alarms(self):
        warning_alarms, mute_alarms = [], []
        for alarm in self.all_subscribe_alarms:
            if alarm.severity in ['warning', 'fatal']:
                warning_alarms.append(alarm)
            else:
                mute_alarms.append(alarm)
        return warning_alarms, mute_alarms

    @staticmethod
    def _format_subscribe_alarms(alarms: list[Alarm]):
        c = AlarmsSeverityClassifier()
        return c.classify_alarms(alarms)

    @staticmethod
    def get_id_alarm_mapping(alarms):
        mapping = {}
        for alarm in alarms:
            if alarm.alarm_id not in mapping:
                mapping[alarm.alarm_id] = alarm
        return mapping

    def handle(self):
        ll.get_logger().info(f'Start handle {self.subscribe_type} {len(self.all_subscribe_alarms)}.')
        new_alarms, recovered_alarms = self._compare(self.warning_alarms, self.current_redis_subscribe_alarms)
        CurrentAlarmsManager.send_new_alarms(new_alarms)
        CurrentAlarmsManager.send_recovered_alarms(recovered_alarms)
        self._refresh_current_alarms()
        self._refresh_all_alarms()
        ll.get_logger().info(f'Handle finish.')

    @staticmethod
    def _compare(sub_alarms, redis_alarms):
        if redis_alarms is None:
            redis_alarms = []
        sub_alarms_mapping = CurrentAlarmsManager.get_id_alarm_mapping(sub_alarms)
        redis_alarms_mapping = CurrentAlarmsManager.get_id_alarm_mapping(redis_alarms)
        new_alarms_mapping = {}
        recovered_alarms_mapping = {}
        for alarm_id, alarm in sub_alarms_mapping.items():
            if alarm_id not in redis_alarms_mapping:
                new_alarms_mapping[alarm_id] = alarm
        for alarm_id, alarm in redis_alarms_mapping.items():
            if alarm_id not in sub_alarms_mapping:
                recovered_alarms_mapping[alarm_id] = alarm
        new_alarms = []
        recovered_alarms = []
        for _, v in new_alarms_mapping.items():
            new_alarms.append(v)
        for _, v in recovered_alarms_mapping.items():
            recovered_alarms.append(v)
        return new_alarms, recovered_alarms

    def _refresh_redis(self, k, v):
        self.redis_client.insert(key=k, value=v)

    @staticmethod
    def _get_client():
        return RedisClient(host=REDIS_SERVER_INFO['host'], port=REDIS_SERVER_INFO['port'])

    def get_current_alarms(self, key):
        b = self.redis_client.get(key)
        if b is None:
            return []
        return json.loads(str(b, 'utf-8'))

    def update_current_alarms(self, key, alarms):
        alarms = self._transform_alarms(alarms)
        self.redis_client.insert(key, alarms)

    @staticmethod
    def send_new_alarms(new_alarms: list[Alarm]):
        AlarmSender.send_warning(new_alarms)

    @staticmethod
    def send_recovered_alarms(recovered_alarms):
        AlarmSender.send_recovery(recovered_alarms)

    @staticmethod
    def _transform_alarms(alarms: list[Alarm]):
        ret = []
        for a in alarms:
            b = a.to_json()
            ret.append(b)
        return ret

    def _refresh_current_alarms(self):
        k = RedisKeysUtil.get_current_problem_key_by_publisher(self.subscribe_type)
        self.update_current_alarms(k, self.warning_alarms)

    def _refresh_all_alarms(self):
        k = RedisKeysUtil.get_all_problem_key_by_publisher(self.subscribe_type)
        self.update_current_alarms(k, self.all_subscribe_alarms)

    def _get_current_warning_from_redis(self):
        data = self.get_current_alarms(RedisKeysUtil.get_current_problem_key_by_publisher(self.subscribe_type))

        ret = []
        for alarm in data:
            alarm = Alarm.json_to_obj(alarm)
            ret.append(alarm)
        return ret
